<?php

namespace app\admin\server;

use Psr\SimpleCache\InvalidArgumentException;
use think\Cache;
use think\cache\driver\Redis;
use think\Exception;

//需要使用到的类

class RedisServer
{
    public static $instance = null;

    public function __construct()
    {
//        self::$instance = new Redis(Config::get('cache.stores.redis'));
        self::$instance = Cache::store('redis');
    }

    public static function getInstance()
    {
        if(is_null(self::$instance)) {
//            self::$instance = new Redis(Config::get('cache.stores.redis'));
            self::$instance = new Redis(config('cache.redis'));
        }
        if(!static::$instance) {
            throw new Exception('redis:异常');
        }
        // $redis->select(1);  // 切换数据库DB
        return static::$instance;
    }


    /**
     * @param string       $redis_key       redis key
     * @param array|string $data            缓存数据
     * @param int          $time_in_seconds 过期时间(多长时间过期 秒(s))
     * @return true
     * @throws Exception
     * @throws InvalidArgumentException
     */
    public static function setStringRedis(string $redis_key, $data, int $time_in_seconds = 60 * 10)
    {
        $time_in_seconds = bcadd((int)$time_in_seconds, mt_rand(1, 10));
        try {
            $redis = RedisServer::getInstance();
//            $redis->SETEX($redis_key, $time_in_seconds, json_encode($data, JSON_UNESCAPED_UNICODE));

            is_array($data) && $data = json_encode($data, JSON_UNESCAPED_UNICODE);

            $redis->SET($redis_key, $data);
//            $redis->expire($redis_key, $time_in_seconds);
            self::setRedisExpire($redis_key, $time_in_seconds);
            return true;
        } catch(Exception $e) {
            throw new Exception($e->getMessage());
        }
    }

    public static function getStringRedis(string $redis_key, $time_in_seconds = 60 * 10)
    {
        $time_in_seconds = bcadd((int)$time_in_seconds, mt_rand(1, 10));
        try {
            $redis = self::getInstance();
            $redis_name = '';
            if($redis->EXISTS(env('CACHE.PREFIX') . $redis_key)) {
                $redis_name = env('CACHE.PREFIX') . $redis_key;
            } else {
                $redis->EXISTS($redis_key) && $redis_name = $redis_key;
            }
            if($redis_name) {
                $data = $redis->get($redis_key);
                !$data && $data = $redis->get($redis_name);
                if($data) {
                    $_data = json_decode($data, true);
                    $_data && $data = $_data;
                }
                return $data;
            }
            return [];
        } catch(Exception $e) {
            throw new Exception($e->getMessage());
        }
    }


    public static function setHashRedis(string $redis_key, $field, array $data, int $time_in_seconds)
    {
        $time_in_seconds = bcadd((int)$time_in_seconds, mt_rand(1, 10));
        try {
            $redis = RedisServer::getInstance();
            $redis->HSET($redis_key, $field, json_encode($data, JSON_UNESCAPED_UNICODE));
            $redis->expire($redis_key, $time_in_seconds);
            return true;
        } catch(Exception $e) {
            throw new Exception($e->getMessage());
        }
    }

    public static function getHashRedis(string $redis_key, $field = '')
    {
        try {
            $redis = RedisServer::getInstance();
//            if(!RedisServer::redisExists($redis_key)) {
            if(!$redis->EXISTS($redis_key)) {
                return [];
            }
            if($field) {
                if(!$redis->HEXISTS($redis_key, $field)) {
                    return [];
                }
                $data = $redis->HGET($redis_key, $field);
            } else {
                $data = $redis->HGETALL($redis_key);
            }
            if($data) {
                if(is_string($data)) {
                    $data = json_decode($data, true);
                } else {
                    foreach($data as &$item) {
                        $item = json_decode($item, true);
                    }
                    unset($item);
                }
            }
            return $data;
        } catch(Exception $e) {
            throw new Exception($e->getMessage());
        }
    }

    public static function redisExists(string $redis_key)
    {
        $redis = RedisServer::getInstance();
        if($redis->EXISTS($redis_key)) {
            return true;
        } else {
            if($redis->EXISTS(env('CACHE.PREFIX') . $redis_key)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 获取剩余过期时间
     * @param string $redis_key
     * @return false|int
     * @throws Exception
     */
    public static function getRedisTtl(string $redis_key)
    {
        $redis = RedisServer::getInstance();
        $redis_name = '';
        if($redis->EXISTS(env('CACHE.PREFIX') . $redis_key)) {
            $redis_name = env('CACHE.PREFIX') . $redis_key;
        } else {
            $redis->EXISTS($redis_key) && $redis_name = $redis_key;
        }
        if($redis_name) {
            return $redis->ttl($redis_name) >= 0 ? $redis->ttl($redis_name) : 0;
        }
        return false;
    }

    /**
     * 设置key 的过期时间
     * @param string $redis_key
     * @param int    $time_in_seconds
     * @return false
     * @throws Exception
     */
    public static function setRedisExpire(string $redis_key, int $time_in_seconds)
    {
        $redis = RedisServer::getInstance();
        if($redis->EXISTS(env('CACHE.PREFIX') . $redis_key)) {
            $redis_name = env('CACHE.PREFIX') . $redis_key;
            return $redis->expire($redis_name, $time_in_seconds);
        } else {
            if($redis->EXISTS($redis_key)) {
                return $redis->expire($redis_key, $time_in_seconds);
            }
        }
        return false;
    }

    /**
     * 获取：长度 / 数量
     * @param string $redis_key
     * @return int
     * @throws Exception
     */
    public static function getLenRedis(string $redis_key)
    {
        $redis_name = '';
        $redis = RedisServer::getInstance();
        if($redis->EXISTS(env('CACHE.PREFIX') . $redis_key)) {
            $redis_name = env('CACHE.PREFIX') . $redis_key;
        } else {
            $redis->EXISTS($redis_key) && $redis_name = $redis_key;
        }
        $len = 0;
        if($redis_name) {
            $len = $redis->STRLEN($redis_name) ?: ($redis->STRLEN($redis_key) ?: 0);  // 字符串

            !$len && $len = $redis->HLEN($redis_name) ?: ($redis->HLEN($redis_key) ?: 0);  // hash

            !$len && $len = $redis->LLEN($redis_name) ?: ($redis->LLEN($redis_key) ?: 0);  // 列表(List)

            !$len && $len = $redis->SCARD($redis_name) ?: ($redis->SCARD($redis_key) ?: 0);  //集合(Set)

            !$len && $len = $redis->ZCARD($redis_name) ?: ($redis->ZCARD($redis_key) ?: 0); //有序集合(sorted set)
        }
        return $len;
    }


}
